home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 10
/
FM Towns Free Software Collection 10.iso
/
ms_dos
/
tool
/
mercury
/
textview.c
< prev
next >
Wrap
Text File
|
1995-02-05
|
16KB
|
706 lines
/*
MercuryInstaller テキストビュワールーチン
*/
#include<stdio.h>
#include<stdlib.h>
#include<jctype.h>
#include<string.h>
#include<jstring.h>
#include<farstr.h>
#include<dos.h>
#include<stdarg.h>
#include<LHACCESS.H>
#include"mercury.h"
/*===========================================================================*/
/* 定数と変数 */
/*===========================================================================*/
#define TEXT_STARTYPOS 3 /* テキスト表示開始位置 */
#define TEXT_YWIDTH (CON_YWIDTH-TEXT_STARTYPOS)
/* テキスト表示行数(putmessage専用行は除いてある) */
static char far **Text; /* テキストバッファ */
static int Linenum; /* テキストの総行数 */
static int Linepos; /* 現在表示中の内容の開始行番号 */
static int Bufsize; /* バッファの行数 */
/*===========================================================================*/
/* ファイル読み込み関連 */
/*===========================================================================*/
/*------------------------------メモリの確保---------------------------------*/
/* まず指定容量のメモリの確保を試み、失敗した場合は少しずつ容量を減らしてゆく*/
/*---------------------------------------------------------------------------*/
static void *nearcalloc_down(size_t num,size_t width,size_t *ret)
{
void *p;
while ((p=calloc(num,width))==NULL && num>1)
num--;
if (p==NULL)
*ret = 0;
else
*ret = num;
return p;
}
static void far *maxfarmalloc(long *size)
{
long s = farcoreleft();
void far *p;
do
{
p = farmalloc(s);
if (p!=NULL)
{
*size = s;
return p;
}
} while(--s);
return NULL;
}
/*-----------------------------仮想ファイルの処理----------------------------*/
/* LHACCESSライブラリを経由した書庫ファイルか、それとも単なるベタテキストかを*/
/* 全く意識せずに使用するためのルーチン */
/*---------------------------------------------------------------------------*/
static struct
{
enum {NONE,LZH,TEXT} mode;
union
{
FILE *fp;
ROOT root;
} pointer;
} File;
static int File_ungetc;
static void file_open(char *filename)
{
char *p = jstrchr(filename,'|');
File_ungetc = EOF;
if (p!=NULL) /* 書庫ファイルを通したアクセス */
{
*p = '\0';
if (islzh(filename)!=0 ||
open_root(filename,&File.pointer.root)!=0)
{
*p = '|';
goto error;
}
*p = '|';
if (get_all_header(&File.pointer.root)!=0 ||
lzh_fopen2(&File.pointer.root,p+1)!=0 )
{
close_root(&File.pointer.root);
goto error;
}
File.mode = LZH;
return;
}
else
{
if ((File.pointer.fp=fopen(filename,"r"))==NULL)
goto error;
File.mode = TEXT;
return;
}
error:
File.mode = NONE;
return;
}
static void file_close(void)
{
switch (File.mode)
{
case LZH:
close_root(&File.pointer.root);
break;
case TEXT:
fclose(File.pointer.fp);
break;
}
}
static int file_getc(void)
{
int c;
if (File_ungetc!=EOF)
{
c = File_ungetc;
File_ungetc = EOF;
return c;
}
switch (File.mode)
{
case NONE:
return EOF;
case LZH:
do
c = lzh_fgetc();
while (c=='\r' || c=='\x1a');
return c;
case TEXT:
return fgetc(File.pointer.fp);
}
}
#define file_ungetc(c) (File_ungetc=(c))
/*---------------------------テキストの読み込み------------------------------*/
static bool readfile(char *filename)
{
char far *p;
int xlen=0;
int c;
int isknj = 0;
long bufsize,buf_left;
file_open(filename);
Linenum = 0;
Text = nearcalloc_down(4096,sizeof(char far *),&Bufsize);
if (Text==NULL)
{
putmessage("メモリ不足です");
return 0;
}
p = Text[0] = maxfarmalloc(&bufsize);
buf_left = bufsize;
while ((c=file_getc())!=EOF)
{
*p++ = c;
buf_left--;
if (c=='\t')
xlen += CON_TABSIZE - xlen%CON_TABSIZE;
else
xlen++;
if (!isknj && iskanji(c))
isknj = 1;
else
isknj = 0;
if (xlen>=CON_XWIDTH || c=='\n')
{
if (isknj)
{
file_ungetc(c);
p--;
buf_left++;
isknj = 0;
}
*p = '\0';
xlen = 0;
if (++Linenum == Bufsize)
{
putmessage("行数が多すぎるので途中で打ち切ります");
break;
}
p += 1L;
Text[Linenum] = p;
buf_left--;
}
if (buf_left<2)
{
putmessage("メモリ不足です 途中で打ち切ります;bufsize=%ld,buf_left=%ld",bufsize,buf_left);
break;
}
}
if (xlen)
{
*p = '\0';
Linenum++;
}
if (Linenum==0)
{
farfree(Text[0]);
free(Text);
}
else
{
farrealloc(Text[0],bufsize-buf_left);
realloc(Text,Linenum*sizeof(Text[0]));
}
file_close();
return 1;
}
/*--------------------------ファイルバッファの解放---------------------------*/
static void memory_release(void)
{
if (Linenum>0)
{
farfree(Text[0]);
free(Text);
}
}
/*-----------------------------パス名の生成----------------------------------*/
static void mkpath(char *buf,char far *dir,char far *filename)
{
if (dir==NULL || filename[1]==':')
buf[0] = '\0';
else
{
buf[0] = Drive;
buf[1] = ':';
if (filename[0]!='\\')
{
if (dir!=NULL)
far_strcpy(buf+2,dir);
else
buf[2] = '\0';
strcat(buf,"\\");
}
else
buf[2] = '\0';
}
far_strcat(buf,filename);
}
/*-----------------------------ファイルの検索--------------------------------*/
/* ○指定されたディレクトリからファイルを検索し、最初に見つかったファイルの */
/* ファイル名をbufに返す。 */
/* ○ファイルが見つからない場合は、bufに空文字列をセットする。 */
/* ○なお、dirはDataから引っ張ってくる関係でfarポインタになっている。 */
/*---------------------------------------------------------------------------*/
static bool findfile(char far *dir,char *wildcard,char buf[])
{
char *p;
struct find_t fib;
mkpath(buf,dir,wildcard);
if ((p=jstrrchr(buf,'\\'))!=NULL)
p++;
else if (buf[1]==':')
p = buf+2;
else
p = buf;
if (_dos_findfirst(buf,_A_NORMAL,&fib)==0)
{
strcpy(p,fib.name);
return 1;
}
else
{
buf[0] = '\0';
return 0;
}
}
/*===========================================================================*/
/* 画面表示関連(1):テキストのスクロール */
/*===========================================================================*/
/*----------------------------------行を表示---------------------------------*/
static void showoneline(int ypos)
{
printf("\033[%d;1f\033[2K",ypos+TEXT_STARTYPOS);
if (Linepos+ypos>=Linenum)
return;
far_fputs(Text[Linepos+ypos],stdout);
}
/*---------------------画面全体の表示(インライン関数)------------------------*/
#define showtext() do \
{ \
int i; \
\
for (i=0 ; i<TEXT_YWIDTH ; i++) \
showoneline(i); \
} while(0)
/*-------------------------------画面の初期化--------------------------------*/
static void screen_init(char far *title,char *filename)
{
static char far *title_save;
static char *filename_save;
char buf[TITLEWIDTH+1];
if (title==NULL)
title = title_save;
else
title_save = title;
if (filename==NULL)
filename = filename_save;
else
filename_save = filename;
far_strcpy(buf,title);
printf("\033[2J\033[7;36m%-*s\033[37;7m%-*s\n",TITLEWIDTH,buf,
CON_XWIDTH-TITLEWIDTH," [F5]HELP");
printf("\033[2;1f\033[7;36m%-*s\033[0m",CON_XWIDTH,filename);
showtext();
}
/*-----------------------------画面のスクロール------------------------------*/
static void scrolldown(void)
{
if (Linepos==Linenum-1)
return;
Linepos++;
printf("\033[%d;1f",TEXT_STARTYPOS);
if (Flag_isfmesc) printf("\033R");
else printf("\033[M");
showoneline(TEXT_YWIDTH-1);
}
static void scrollup(void)
{
if (Linepos==0)
return;
Linepos--;
printf("\033[%d;1f",TEXT_STARTYPOS);
if (Flag_isfmesc) printf("\033E");
else printf("\033[L");
printf("\033[%d;1f\033[2K",TEXT_STARTYPOS+TEXT_YWIDTH);
showoneline(0);
}
/*===========================================================================*/
/* 画面表示関連(2):ウィンドウシステムライブラリ */
/*===========================================================================*/
/* これらの関数はtextviewer()の下でしか使えないので要注意。 */
/*===========================================================================*/
static struct
{
int xstart,ystart; /* 文字表示開始xy座標 */
int xsize,ysize; /* ウィンドウのサイズ */
} Window;
/*-----------------------------ウィンドウを開く------------------------------*/
extern void openwindow(int ysize,int xsize)
{
int i;
Window.ysize = ysize;
Window.xsize = xsize;
Window.xstart = (CON_XWIDTH-xsize)/2;
Window.ystart = (CON_YWIDTH-ysize)/2;
printf("\033[%d;%df\033[36m+",Window.ystart-1,Window.xstart-1);
for (i=0 ; i<Window.xsize ; i++)
putchar('-');
printf("+\033[%d;%df+",Window.ystart+Window.ysize,Window.xstart-1);
for (i=0 ; i<Window.xsize ; i++)
putchar('-');
putchar('+');
for (i=0 ; i<Window.ysize ; i++)
{
printf("\033[%d;%df|%*s|",Window.ystart+i,Window.xstart-1,
Window.xsize,"");
}
printf("\033[0m");
}
/*----------------------------ウィンドウを閉じる-----------------------------*/
extern void closewindow(void)
{
int i;
for (i=-1 ; i<=Window.ysize ; i++)
showoneline(Window.ystart+i-TEXT_STARTYPOS);
}
/*--------------------------------文字列の出力-------------------------------*/
/* ウィンドウの各行の最後の1バイトは全角文字の禁則処理専用に予約済。 */
/*---------------------------------------------------------------------------*/
extern void window_putstr(int ypos,char *format,...)
{
va_list ap;
char buf[256];
char *p = buf;
char c;
int xpos = 0;
va_start(ap,format);
vsprintf(buf,format,ap);
while ((c=*p++)!='\0')
{
if (xpos==0)
printf("\033[%d;%df%*s\033[%d;%df",
Window.ystart+ypos,Window.xstart,
Window.xsize,"",
Window.ystart+ypos,Window.xstart);
putchar(c);
xpos++;
if (iskanji(c))
{
putchar(*p++);
xpos++;
}
if (xpos>=Window.xsize-1 || c=='\n')
{
ypos++;
xpos = 0;
}
}
}
/*-----------------------------文字列を入力する------------------------------*/
/* 0<strlen(message)≦len≦CON_XWIDTH-5。ただしチェックはしない */
/*---------------------------------------------------------------------------*/
extern int window_strinput(char *message,char *buf,unsigned len)
{
int f;
openwindow(2,len+3);
window_putstr(0,"%s",message);
window_putstr(1,"[%*s]",len,"");
showcursor(1);
printf("\033[%d;%df",Window.ystart+1,Window.xstart+1);
f = ds_strinput(buf,len);
showcursor(0);
closewindow();
return f;
}
/*---------------------選択肢を提示して入力を求める--------------------------*/
/* messageは最大で64バイト×3行におさまること。ただしチェックはしない */
/*---------------------------------------------------------------------------*/
/* messageの後には、16個以下のconst char *が続く。たとえば"Abort"や"I:中止"の*/
/* ように、先頭の1バイトは入力する際の文字ともなる。なお1行に収まるようにする*/
/* こと */
/*---------------------------------------------------------------------------*/
extern int window_select(char *message,...)
{
char letter[16];
char buf[256];
char *p;
int n=0;
va_list ap;
va_start(ap,message);
openwindow(4,64);
window_putstr(0,"%s",message);
buf[0] = '\0';
while ((p=va_arg(ap,char *))!=NULL)
{
strcat(buf,p);
strcat(buf," ");
letter[n++] = toupper(*p);
}
va_end(ap);
window_putstr(3,"%s",buf);
while (1)
{
int c = ds_getch();
int i;
if (c>=0x100)
continue;
c = toupper(c);
for (i=0 ; i<n ; i++)
{
if (letter[i]==c)
{
closewindow();
return c;
}
}
}
}
/*===========================================================================*/
/* 各種コマンド */
/*===========================================================================*/
/*-------------------印刷(厳密には他のファイルへの出力)----------------------*/
static void printout(void)
{
static char filename[128] = "\\dev\\prn";
char buf[128];
FILE *fp;
int i;
strcpy(buf,filename);
if (!window_strinput("印刷します 出力先デバイスを指定してください",buf,64))
return;
strcpy(filename,buf);
openwindow(2,64);
fp = fopen(filename,"w");
if (fp==NULL)
{
window_putstr(0,"%sがオープンできません",filename);
closewindow();
return;
}
for (i=0 ; i<Linenum ; i++)
{
if (i%64==0)
window_putstr(0,"出力中 %d/%d",i,Linenum);
/* 中止の確認はint24Hハンドラがやってくれているはず */
if (far_fputs(Text[i],fp))
{
window_putstr(0,"中止しました");
goto error;
}
}
window_putstr(0,"終了しました");
error:
ds_getch();
closewindow();
fclose(fp);
}
/*------------------------------ヘルプの出力---------------------------------*/
static void helpmessage(void)
{
int i;
static char *message[] =
{
"[↑][↓] スクロール",
"[F1] 概要ファイル/マニュアル切り替え",
"[F2] 現在見ているファイルの印刷",
"[F3] インストール",
"[F4] DOSコマンドライン",
"[F5] ヘルプ(この画面)",
"[ESC][F10] 終了",
};
openwindow(MEMBERSOF(message),64);
for (i=0 ; i<MEMBERSOF(message) ; i++)
window_putstr(i,message[i]);
ds_getch();
closewindow();
}
/*===========================================================================*/
/* テキストビュワーのメインルーチン */
/*===========================================================================*/
extern void textviewer(struct DATA far *data)
{
char filename[2][256]; /* GGG/MANのファイル名 */
bool ismanual = 0;
if (data->readme!=NULL)
mkpath(filename[0],data->dir,data->readme);
else if (findfile(data->dir,"*.ggg" ,filename[0])) ;
else if (findfile(data->dir,"!*.*" ,filename[0])) ;
else if (findfile(data->dir,"read*.*",filename[0])) ;
else if (findfile(data->dir,"*.doc" ,filename[0])) ;
if (data->manual!=NULL)
mkpath(filename[1],data->dir,data->manual);
else if (findfile(data->dir,"*.rrr",filename[1])) ;
else if (findfile(data->dir,"*.man",filename[1])) ;
else if (findfile(data->dir,"*.doc",filename[1])) ;
again:
readfile(filename[ismanual]);
Linepos = 0;
screen_init(data->title,filename[ismanual]);
while (1)
{
switch (ds_getch())
{
case FKEY_UP:
scrollup();
break;
case FKEY_DOWN:
scrolldown();
break;
case FKEY_LEFT:
if ((Linepos-=TEXT_YWIDTH)<0)
Linepos=0;
showtext();
break;
case FKEY_RIGHT:
if ((Linepos+=TEXT_YWIDTH)>=Linenum)
Linepos = Linenum-1;
showtext();
break;
case FKEY_F1:
ismanual = !ismanual;
memory_release();
goto again;
case FKEY_F2:
printout();
break;
case FKEY_F3:
installer(data);
break;
case FKEY_F4:
showcursor(1);
printf("\033[2J");
system("");
showcursor(0);
screen_init(NULL,NULL);
break;
case FKEY_F5:
helpmessage();
break;
case FKEY_F10:
case FKEY_ESC:
memory_release();
return; /* 画面を元に戻すのは親関数の仕事 */
}
}
}
/*---------------------------End of textviewer.c-----------------------------*/